#ifndef _CURL_MANAGER_H_
#define _CURL_MANAGER_H_

#include "Thread.h"
#include <deque>
#include <string>

#ifdef _USE_CURL_

typedef void (*OnDataStart)(const std::string &userdata);
typedef size_t (*OnData)(const std::string &userdata, void *ptr, size_t size, size_t nmemb);
typedef void (*OnDataEnd)(const std::string &userdata, const std::string &rsp);
typedef int (*OnProgress)(const std::string userdata, double dltotal, double dlnow, double ultotal, double ulnow);

class CCurlObject : public SGLib::IRunnable
{
public:
    CCurlObject();
    virtual ~CCurlObject();
    bool Start();
    void Stop();
    virtual void Run();

    void PostRequest(const std::string &url, const std::string &postdata, s32 timeOut=5);
    void PostRequest4Data(const std::string &url, const std::string &postdata, OnDataStart onStart, OnData onData, OnDataEnd onEnd, const std::string &userdata, s32 timeOut=30);
    void Download(const std::string &url, const std::string &postdata, OnDataStart onStart, OnData onData, OnDataEnd onEnd, OnProgress onProgress, const std::string &userdata, s32 timeOut=30);

private:

    struct curlReq
    {
        curlReq() : url(""), postdata(""), timeOut(0), rsp(""),
            needReadData(false), userdata(""), onDataStart(NULL), onData(NULL), onDataEnd(NULL),
            needProgress(false), onProgress(NULL)
        {}

        std::string url;
        std::string postdata;
        s32 timeOut;
        std::string rsp;

        bool needReadData;
        std::string userdata;
        OnDataStart onDataStart;
        OnData onData;
        OnDataEnd onDataEnd;

        bool needProgress;
        OnProgress onProgress;
    };

    void _DoAddRequest(curlReq &req);
    void _DoPostData(curlReq &req);

    static size_t _curl_writeCallback(void *ptr, size_t size, size_t nmemb, void *stream);
    static int _curl_progressCallback(void *client, double dltotal, double dlnow, double ultotal, double ulnow);

private:
    SGLib::CEvent m_workSignal;
    SGLib::CThread *m_worker;
    bool m_isStop;

    SGLib::CLock m_lock;
    std::deque<curlReq> m_reqQue;
};

class CCurlManager
{
    SINGLETON_CLASS_DEFINE(CCurlManager);

public:
    // count=0 : not use curl
    void Init(s32 count=1);
    bool Start();
    void Stop();
    
    void PostRequest(const std::string &url, const std::string &postdata, s32 timeOut=5);
    void PostRequest4Data(const std::string &url, const std::string &postdata, OnDataStart onStart, OnData onData, OnDataEnd onEnd, const std::string &userdata, s32 timeOut=30);
    void Download(const std::string &url, const std::string &postdata, OnDataStart onStart, OnData onData, OnDataEnd onEnd, OnProgress onProgress, const std::string &userdata, s32 timeOut=30);

private:
    CCurlObject* _getNextCurlObject();

private:
    s32 m_count;
    CCurlObject **m_curls;
    
    s32 m_idx;
    SGLib::CLock m_lock;
};


#endif

#endif

